#include <stdio.h>
#include "run1.h"
int run1(BODY *root, SymbolTable *symboltable) {
	run1DECL_LIST(root->decl_list, symboltable);
	return run1Error;
}
void run1DECL_LIST(DECL_LIST *decl_list, SymbolTable *symboltable) {
	if (!decl_list == 0) {
		run1DECL_LIST(decl_list->decl_list, symboltable);
		run1DECLARATION(decl_list->declaration, symboltable);
	}
}
void run1DECLARATION(DECLARATION *declaration, SymbolTable *symboltable) {
	FUNCTION *function;
	HEAD *head;
	BODY *body;
	SYMBOL *symbol;
	PAR_DECL_LIST *par_decl_list;
	switch (declaration->kind) {
	case typeidK:
		symbol = putSymbolType(symboltable, declaration->val.DECL_TYPE.id,
				declaration->val.DECL_TYPE.type);
		if (symbol == NULL) {
			run1Error++;
			fprintf(stderr, "Error:%d: Redefinition of '%s'\n",
					declaration->lineno, declaration->val.DECL_TYPE.id);
			fprintf(stderr,
					"\tNote:%d: Previous definition of '%s' was here\n",
					run1LINENO(symbol), declaration->val.DECL_TYPE.id);
		} else {
			run1TYPE(declaration->val.DECL_TYPE.type, symboltable);
		}

		break;
	case funcK:
		function = declaration->val.function;
		head = function->head;
		body = function->body;
		symbol = putSymbolFunction(symboltable, head->id, function);
		if (symbol == NULL){
			run1Error++;
			fprintf(stderr, "Error:%d: Redefinition of '%s'\n", head->lineno,
					head->id);
			fprintf(stderr,
					"\tNote:%d: Previous definition of '%s' was here\n",
					run1LINENO(symbol), head->id);
		} else {
			function->table = scopeSymbolTable(symboltable);
			par_decl_list = head->par_decl_list;
			if (par_decl_list != 0) {
				run1VAR_DECL_LIST(par_decl_list->var_decl_list, function->table);
			}
			run1DECL_LIST(body->decl_list, function->table);
			run1TYPE(head->type, symboltable);
		}
		break;
	case varK:
		run1VAR_DECL_LIST(declaration->val.var_decl_list, symboltable);
		break;
	}
}
int run1LINENO(SYMBOL *symbol) {
	TYPE *type;
	FUNCTION *function;
	VAR_TYPE *var_type;
	switch (symbol->kind) {
	case typeSK:
		type = symbol->val.type;
		return type->lineno;
		break;
	case functionSK:
		function = symbol->val.function;
		return function->lineno;
		break;
	case variableSK:
		var_type = symbol->val.var_type;
		return var_type->lineno;
		break;
	}
	return -42;
}
void run1VAR_DECL_LIST(VAR_DECL_LIST *var_decl_list, SymbolTable *symboltable) {
	switch (var_decl_list->kind) {
	case var_decl_listK:
		run1VAR_DECL_LIST(var_decl_list->var_decl_list, symboltable);
		run1VAR_TYPE(var_decl_list->var_type, symboltable);
		break;
	case var_decl_list_baseK:
		run1VAR_TYPE(var_decl_list->var_type, symboltable);
		break;
	}
}
void run1VAR_TYPE(VAR_TYPE *var_type, SymbolTable *symboltable) {
	SYMBOL *symbol;
	symbol = putSymbolVariable(symboltable, var_type->id, var_type);
	if (symbol == NULL) {
		run1Error++;
		fprintf(stderr, "Error:%d: Redefinition of '%s'\n", var_type->lineno,
				var_type->id);
		fprintf(stderr, "\tNote:%d: Previous definition of '%s' was here\n",
				run1LINENO(symbol), var_type->id);
	} else {
		run1TYPE(var_type->type, symboltable);
	}
}
void run1TYPE(TYPE *type, SymbolTable *symboltable) {
	if (type->kind == recordK) {
		type->val.recordE.table = initSymbolTable();
		run1VAR_DECL_LIST(type->val.recordE.var_decl_list,
				type->val.recordE.table);
	} else if (type->kind == arrayK) {
		run1TYPE(type->val.type, symboltable);
	}
}
